package org.linuxsogood.boot.config;

import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import java.net.URI;

/**
 * http://www.zhyea.com/2017/10/10/wrap-spring-boot-controller-response.html
 * 如果Controller类的返回值没有String类型的，
 * 仅有上面这个类就够了。如果有String类型的返回值，
 * 就有可能遇到类型不匹配的问题。HttpMessageConverter是根据Controller的原始返回值类型进行处理的，
 * 而我们在ResponseAdvisor中改变了返回值的类型。如果HttpMessageConverter处理的目标类型是Object还好说，
 * 如果是其它类型就会出现问题，其中最容易出现问题的就是String类型，
 * 因为在所有的HttpMessageConverter实例集合中，StringHttpMessageConverter要比其它的Converter排得靠前一些。
 * 我们需要尝试将处理Object类型的HttpMessageConverter放得靠前一些，这可以在Configuration类中完成
 * @author honway.liu
 * @date 2018/8/5 下午9:50
 * @email gm100861@gmail.com
 * @blog http://linuxsogood.org
 */
@ControllerAdvice
public class ResponseAdvisor implements ResponseBodyAdvice<Object> {

    @Override
    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        URI uri = serverHttpRequest.getURI();
        if (!uri.getPath().startsWith("/api")) {
            return body;
        }
        if (body instanceof ApiResponse) {
            return body;
        }
        ApiResponse response = new ApiResponse();
        response.setData(body);
        return response;
    }
}
